// Zig 代码生成器 - 不依赖 std
const cz_std = @import("cz_std.zig");
const parser = @import("parser.zig");
const array_list = @import("array_list.zig");
const ArrayList = array_list.ArrayList;
const arrayListWriter = array_list.arrayListWriter;
const Allocator = cz_std.Allocator;

// 主入口函数
pub fn generate(allocator: Allocator, ast: parser.AST) ![]u8 {
    return generateZig(allocator, ast);
}

pub fn generateZig(allocator: Allocator, ast: parser.AST) ![]u8 {
    var buffer = ArrayList(u8).init(allocator);
    defer buffer.deinit();
    
    var writer_ctx = arrayListWriter(&buffer);
    
    // 生成标准库导入
    try writer_ctx.print("const std = @import(\"std\");\n\n", .{});
    
    // 遍历AST节点生成代码
    for (ast.items) |item| {
        switch (item) {
            .import_decl => |import_decl| {
                try generateImport(&writer_ctx, import_decl);
            },
            .function_decl => |func_decl| {
                try generateFunction(&writer_ctx, func_decl);
            },
            .var_decl => |var_decl| {
                try generateVarDecl(&writer_ctx, var_decl);
            },
            .expr_stmt => |expr| {
                try writer_ctx.print("pub fn main() !void {{\n", .{});
                try generateExpression(&writer_ctx, expr, 1);
                try writer_ctx.print(";\n}}\n", .{});
            },
            else => {
                // 忽略其他节点类型
            },
        }
    }
    
    // 如果没有生成main函数，则添加一个默认的
    if (buffer.items.len > 0 and cz_std.indexOf(buffer.items, "pub fn main()") == null) {
        try writer_ctx.print("\npub fn main() !void {{\n    // 默认main函数\n}}\n", .{});
    }
    
    return buffer.toOwnedSlice();
}

fn generateImport(writer: anytype, import_decl: parser.ImportDecl) !void {
    try writer.print("const {s} = @import(\"{s}\");\n", .{ import_decl.module_path, import_decl.module_path });
}

fn generateFunction(writer: anytype, func_decl: parser.FunctionDecl) !void {
    // 输出pub关键字
    if (func_decl.is_public) {
        try writer.print("pub ", .{});
    }
    
    try writer.print("fn {s}(", .{func_decl.name});
    
    // 输出参数
    for (func_decl.params, 0..) |param, i| {
        if (i > 0) {
            try writer.print(", ", .{});
        }
        try writer.print("{s}: {s}", .{ param.name, param.type });
    }
    
    try writer.print(") ", .{});
    
    // 输出返回类型
    if (func_decl.return_type) |return_type| {
        try writer.print("{s} {{\n", .{return_type});
    } else {
        try writer.print("void {{\n", .{});
    }
    
    // 输出函数体
    for (func_decl.body) |stmt| {
        try generateStatement(writer, stmt, 1);
    }
    
    try writer.print("}}\n\n", .{});
}

fn generateVarDecl(writer: anytype, var_decl: parser.VarDecl) !void {
    // 输出pub关键字
    if (var_decl.is_public) {
        try writer.print("pub ", .{});
    }
    
    // 输出const或var
    if (var_decl.is_const) {
        try writer.print("const ", .{});
    } else {
        try writer.print("var ", .{});
    }
    
    try writer.print("{s}", .{var_decl.name});
    
    // 输出类型注解
    if (var_decl.type) |type_annotation| {
        try writer.print(": {s}", .{type_annotation});
    }
    
    // 输出初始化器
    if (var_decl.initializer) |*initializer| {
        try writer.print(" = ", .{});
        try generateExpression(writer, initializer.*, 0);
    }
    
    try writer.print(";\n", .{});
}

fn generateStatement(writer: anytype, stmt: parser.Statement, indent_level: usize) !void {
    const indent = getIndent(indent_level);
    
    switch (stmt) {
        .expr_stmt => |expr| {
            try writer.print("{s}", .{indent});
            try generateExpression(writer, expr, indent_level);
            try writer.print(";\n", .{});
        },
        .return_stmt => |ret_stmt| {
            try writer.print("{s}return", .{indent});
            if (ret_stmt.value) |*value| {
                try writer.print(" ", .{});
                try generateExpression(writer, value.*, indent_level);
            }
            try writer.print(";\n", .{});
        },
        .var_decl => |var_decl| {
            try writer.print("{s}", .{indent});
            try generateVarDecl(writer, var_decl);
        },
    }
}

fn generateExpression(writer: anytype, expr: parser.Expr, indent_level: usize) !void {
    _ = indent_level; // 暂时未使用
    
    switch (expr) {
        .literal => |literal| {
            switch (literal) {
                .integer => |value| {
                    try writer.print("{d}", .{value});
                },
                .float => |value| {
                    try writer.print("{d}", .{value});
                },
                .string => |value| {
                    try writer.print("\"{s}\"", .{value});
                },
                .boolean => |value| {
                    try writer.print("{}", .{value});
                },
                .null_literal => {
                    try writer.print("null", .{});
                },
            }
        },
        .identifier => |name| {
            try writer.print("{s}", .{name});
        },
        .call => |call_expr| {
            try generateExpression(writer, call_expr.callee.deref().*, 0);
            try writer.print("(", .{});
            
            for (call_expr.arguments, 0..) |arg, i| {
                if (i > 0) {
                    try writer.print(", ", .{});
                }
                try generateExpression(writer, arg, 0);
            }
            
            try writer.print(")", .{});
        },
        .binary => |binary_expr| {
            try generateExpression(writer, binary_expr.left.deref().*, 0);
            try writer.print(" {s} ", .{binary_expr.operator});
            try generateExpression(writer, binary_expr.right.deref().*, 0);
        },
        .unary => |unary_expr| {
            try writer.print("{s}", .{unary_expr.operator});
            try generateExpression(writer, unary_expr.operand.deref().*, 0);
        },
    }
}

fn getIndent(level: usize) []const u8 {
    switch (level) {
        0 => return "",
        1 => return "    ",
        2 => return "        ",
        3 => return "            ",
        4 => return "                ",
        else => return "                    ",
    }
}